//
//  UILabel+LinkTap.m
//  KVO-Demo
//
//  Created by JK210 on 2018/4/12.
//  Copyright © 2018年 JK210. All rights reserved.
//

#import "UILabel+LinkTap.h"
#import <objc/runtime.h>

@interface UILabel ()
@property (nonatomic, strong)NSTextStorage *textStorage;
@property (nonatomic, strong)NSLayoutManager *layoutManager;
@property (nonatomic, strong)NSTextContainer *textContainer;
@property (nonatomic, strong)NSArray * rangesArray;
@property (nonatomic, strong)NSDictionary * tapUrlRangeDict;
@property (nonatomic, copy)WKBTextAction tapAction;
@end

NSString const *WKB_TextStorage = @"WKB_TextStorage";
NSString const *WKB_LayoutManager = @"WKB_LayoutManager";
NSString const *WKB_TextContainer = @"WKB_TextContainer";
NSString const *WKB_UrlRangeArray = @"WKB_UrlRangeArray";
NSString const *WKB_UrlRange = @"WKB_UrlRange";
NSString const *WKB_TextBlock = @"WKB_TextBlock";

@implementation UILabel (LinkTap)

- (void)setRangesArray:(NSArray *)rangesArray
{
    objc_setAssociatedObject(self, &WKB_UrlRangeArray, rangesArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSArray *)rangesArray
{
    return objc_getAssociatedObject(self, &WKB_UrlRangeArray);
}

- (void)setTextStorage:(NSTextStorage *)textStorage
{
    objc_setAssociatedObject(self, &WKB_TextStorage, textStorage, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSTextStorage *)textStorage
{
    return objc_getAssociatedObject(self, &WKB_TextStorage);
}

- (void)setLayoutManager:(NSLayoutManager *)layoutManager
{
    objc_setAssociatedObject(self, &WKB_LayoutManager, layoutManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSLayoutManager *)layoutManager
{
    return objc_getAssociatedObject(self, &WKB_LayoutManager);
}

- (void)setTextContainer:(NSTextContainer *)textContainer
{
    objc_setAssociatedObject(self, &WKB_TextContainer, textContainer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSTextContainer *)textContainer
{
    return objc_getAssociatedObject(self, &WKB_TextContainer);
}

- (void)setTapAction:(WKBTextAction)tapAction
{
    objc_setAssociatedObject(self, &WKB_TextBlock, tapAction, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (WKBTextAction)tapAction
{
    return objc_getAssociatedObject(self, &WKB_TextBlock);
}

- (void)setTapUrlRangeDict:(NSDictionary *)tapUrlRangeDict
{
    objc_setAssociatedObject(self, &WKB_UrlRange, tapUrlRangeDict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSDictionary *)tapUrlRangeDict
{
    return objc_getAssociatedObject(self, &WKB_UrlRange);
}

- (void)tapWithURLTextRanges:(NSArray *)ranges tapAction:(WKBTextAction)action
{
    self.userInteractionEnabled = YES;
    self.tapAction = action;
    self.rangesArray = ranges;
    self.textStorage = [NSTextStorage new];
    self.layoutManager = [NSLayoutManager new];
    self.textContainer = [NSTextContainer new];
    [self.textStorage addLayoutManager:self.layoutManager];
    [self.layoutManager addTextContainer:self.textContainer];
    
    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(labelTapAction:)];
    [self addGestureRecognizer:tapGestureRecognizer];
}

- (void)labelTapAction:(UITapGestureRecognizer *)recognizer
{
    CGPoint location = [recognizer locationInView:recognizer.view];
    self.textContainer.size = self.bounds.size;
    self.textContainer.lineFragmentPadding = 0;
    self.textContainer.maximumNumberOfLines = self.numberOfLines;
    self.textContainer.lineBreakMode = self.lineBreakMode;
    
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
    NSRange textRange = NSMakeRange(0, attributedText.length);
    [attributedText addAttribute:NSFontAttributeName value:self.font range:textRange];
    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
    paragraphStyle.alignment = self.textAlignment;
    [attributedText addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:textRange];
    [self.textStorage setAttributedString:attributedText];
    
    CGSize textSize = [self.layoutManager usedRectForTextContainer:self.textContainer].size;
    
    location.y -= (CGRectGetHeight(self.frame) - textSize.height) / 2;
    
    NSUInteger glyphIndex = [self.layoutManager glyphIndexForPoint:location inTextContainer:self.textContainer];
    CGFloat fontPointSize = self.font.pointSize;
    [self.layoutManager setAttachmentSize:CGSizeMake(fontPointSize, fontPointSize) forGlyphRange:NSMakeRange(self.text.length - 1, 1)];
    NSAttributedString *attributedSubstring = [self.attributedText attributedSubstringFromRange:NSMakeRange(glyphIndex, 1)];
    CGRect glyphRect = [self.layoutManager boundingRectForGlyphRange:NSMakeRange(glyphIndex, 1) inTextContainer:self.textContainer];
    
    if (!CGRectContainsPoint(glyphRect, location)) {
        if (CGRectContainsPoint(CGRectMake(0, 0, textSize.width, textSize.height), location)) {
        }
        return;
    }
    
    for (NSDictionary * rangeDic in self.rangesArray) {
        NSRange range = NSMakeRange([rangeDic[@"loc"] integerValue], [rangeDic[@"len"] integerValue]);
        BOOL isIn = NSLocationInRange(glyphIndex, range);
        if (isIn) {
            self.tapUrlRangeDict = rangeDic;
            [self tapUrlEffectWithBackcolor:[UIColor colorWithWhite:0 alpha:0.3]];
            self.tapAction(glyphIndex, attributedSubstring);
            break;
        }
    }
}

- (void)tapUrlEffectWithBackcolor:(UIColor *)color
{
    NSMutableAttributedString * attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
    [attributedText addAttributes:@{NSBackgroundColorAttributeName:color
                                    } range:NSMakeRange([self.tapUrlRangeDict[@"loc"] integerValue], [self.tapUrlRangeDict[@"len"] integerValue])];
    self.attributedText = attributedText;
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [attributedText removeAttribute:NSBackgroundColorAttributeName range:NSMakeRange([self.tapUrlRangeDict[@"loc"] integerValue], [self.tapUrlRangeDict[@"len"] integerValue])];
        self.attributedText = attributedText;
    });
}
@end
